﻿using FSM;
using QFramework;
using System.Collections.Generic;
using UnityEngine;

namespace PlatformShoot
{
    public class StateName
    {
        public const string Patrol = "Patrol";
        public const string Pursuit = "Pursuit";
        public const string Observe = "Observe";

        public const string GroundMove = "GroundMove";
        public const string GroundIdle = "GroundIdle";

        public const string AirIdle = "AirIdle";
        public const string AirMove = "AirMove";

        public const string Jump = "Jump";
        public const string InAir = "InAir";
    }
    // 使用状态机实现平台类AI
    public class TestAIFsm : RuleFSM<TestAIData, TestAIFsm>, ICanPlayAnim
    {
        private int mFace = 1;
        public int FaceDir => mFace;
        public bool FaceEquals(float dir) => FaceDir == dir;
        public void Filp()
        {
            mFace = -mFace;
            transform.Rotate(0, 180, 0);
        }
        private Rigidbody2D mRig;
        [SerializeField]
        private Vector2 MoveVel;
        // 检测到的射线对象组
        private RaycastHit2D[] hits;
        private Collider2D[] collider2Ds;
        // 射线发射的原点 需要在AI下创建一个游戏物体用来调整射线发射位置
        private Transform mFaceDirGroundCheck;
        private Transform mGroundCheck;
        // 给状态类提供一个射线检测的公开方法 使用 RaycastNonAlloc 来进行检测 这个方法可以减少GC的产生
        public bool CheckFaceDirIsGround =>
            Physics2D.RaycastNonAlloc(mFaceDirGroundCheck.position, Vector2.down, hits, Data.GroundRayLength, Data.GroundLayer) > 0;
        public bool CheckGround =>
            Physics2D.OverlapBoxNonAlloc(mGroundCheck.position, Data.GroundCheckBoxSize, 0, collider2Ds, Data.GroundLayer) > 0;
        public bool ObserveCheck =>
            Physics2D.OverlapBoxNonAlloc(transform.position + Data.ObserveCheckOffset, Data.ObserveCheckBoxSize, 0, collider2Ds, Data.PlayerLayer) > 0;
        public bool PursuitCheck =>
            Physics2D.OverlapBoxNonAlloc(new Vector2(transform.position.x + mFace * Data.PursuitCheckOffset.x, transform.position.y + Data.PursuitCheckOffset.y),
                Data.PursuitCheckBoxSize, 0, collider2Ds, Data.PlayerLayer) > 0;
        public Transform GetColliderTarget(string tag)
        {
            for (int i = 0; i < collider2Ds.Length; i++)
            {                
                if(collider2Ds[i] == null) continue;                
                if (!collider2Ds[i].CompareTag(tag)) continue;
                //Debug.Log("循环" + collider2Ds[i]);
                return collider2Ds[i].transform;
            }
            return null;
        }
        private void Start()
        {
            // 初始化可检测射线的个数 正常两个位置差不多
            hits = new RaycastHit2D[1];
            collider2Ds = new Collider2D[4];
            mRig = GetComponent<Rigidbody2D>();
            // 使用 transform.Find 找到射线检测发射点的变换组件对象
            mFaceDirGroundCheck = transform.Find("GroundCurDirCheck");
            mGroundCheck = transform.Find("GroundCheck");

        }
        private void OnDrawGizmos()
        {
            // 使用 OnDrawGizmos 函数 来渲染出 射线
            if (mFaceDirGroundCheck == null || mGroundCheck == null) return;
            Gizmos.color = Color.red;
            Gizmos.DrawWireCube(new Vector2(transform.position.x + mFace * Data.PursuitCheckOffset.x, transform.position.y + Data.PursuitCheckOffset.y), Data.PursuitCheckBoxSize);
            Gizmos.DrawWireCube(transform.position + Data.ObserveCheckOffset, Data.ObserveCheckBoxSize);
            Gizmos.DrawWireCube(mGroundCheck.position, Data.GroundCheckBoxSize);
            Gizmos.DrawLine(mFaceDirGroundCheck.position, mFaceDirGroundCheck.position + Vector3.down * Data.GroundRayLength);
        }
        public float XSpeed
        {
            get => MoveVel.x;
            set
            {
                MoveVel.x = value;
                MoveVel.y = mRig.velocity.y;
            }
        }
        public float YSpeed
        {
            get => MoveVel.y;
            set
            {
                MoveVel.x = mRig.velocity.x;
                MoveVel.y = value;
            }
        }
        private void FixedUpdate()
        {
            mRig.velocity = MoveVel;
            // Debug.Log("更新" + Data?.GetType().Name);
        }

        public override string DataResPath => "Test/AIDataTest";
        protected override IStateBuilder<E_StateLife> Builder => new TestAIStateBuilder(this, Data);

        // 显式实现 播放动画接口
        void ICanPlayAnim.PlayAnim(int animHash) { }
    }
    public class TestAIStateBuilder : IStateBuilder<E_StateLife>
    {
        private TestAIFsm fsm;
        private TestAIData data;
        public TestAIStateBuilder(TestAIFsm fsm, TestAIData data)
        {
            this.data = data;
            this.fsm = fsm;
            // Debug.Log(fsm?.GetType().Name + data?.GetType().Name);
        }
        Dictionary<string, State<E_StateLife>> IStateBuilder<E_StateLife>.Create(out string firstStateName)
        {
            firstStateName = StateName.AirIdle;

            var ground = new TestAIGroundState().Init(fsm, data);
            var inAir = new TestAIInAirState().Init(fsm, data);

            return new Dictionary<string, State<E_StateLife>>()
            {
                { StateName.Jump ,new TestAIJumpState().SetAnim(StateName.InAir) },

                { StateName.AirIdle ,new TestAIInAirIdleState().SetAnim(StateName.InAir).SetFather(inAir) },
                { StateName.AirMove ,new TestAIInAirMoveState().SetAnim(StateName.InAir).SetFather(inAir) },

                { StateName.Observe ,new TestAIObserveState().SetAnim(StateName.GroundIdle).SetFather(ground) },
                { StateName.Patrol ,new TestAIPatrolState().SetAnim(StateName.GroundMove).SetFather(ground) },
                { StateName.Pursuit ,new TestAIPursuitState().SetAnim(StateName.GroundMove).SetFather(ground) },
            };
        }
    }

    public class TestAIGroundState : BaseState<TestAIFsm, TestAIData>
    {
        private Transform target;
        protected override string CheckCondition()
        {
            if (Machine.CheckGround)
            {
                // 如果检测到玩家并且敌人在地面上 
                if (target != null)
                {
                    Vector2 dis = target.position - Machine.transform.position;
                    // 如果在头顶 就跳一下
                    // Debug.Log(Data);
                    if (dis.y > Data.TriggerJumpRange.y && Mathf.Abs(dis.x) < Data.TriggerJumpRange.x) return StateName.Jump;
                }
            }
            else return StateName.AirIdle;
            return null;
        }

        protected override void Execute(E_StateLife life)
        {
            if (life != E_StateLife.Enter) return;
            if (Machine.ObserveCheck)
            {
                target = Machine.GetColliderTarget("Player");
            }
        }
    }
    public class TestAIJumpState : AnimState<TestAIFsm, TestAIData>
    {
        protected override string CheckCondition() => StateName.AirMove;

        protected override void Execute(E_StateLife life)
        {
            base.Execute(life);

            if (life == E_StateLife.Enter)
            {
                Machine.YSpeed = Data.JumpForce;
            }
        }
    }
    public class TestAIInAirState : BaseState<TestAIFsm, TestAIData>
    {
        protected override string CheckCondition()
        {
            if (Machine.CheckGround) return StateName.Observe;
            return null;
        }

        protected override void Execute(E_StateLife life)
        {
            
        }
    }
    public class TestAIInAirMoveState : AnimState<TestAIFsm, TestAIData>
    {
        protected override string CheckCondition()
        {
            if (!Machine.PursuitCheck && !Machine.ObserveCheck) return StateName.AirIdle;
            return null;
        }
        protected override void Execute(E_StateLife life)
        {
            base.Execute(life);
            // 追击目标
            if (Machine.ObserveCheck || Machine.PursuitCheck)
            {
                float dis = Machine.GetColliderTarget("Player").position.x - Machine.transform.position.x;
                int dir = dis > 0 ? 1 : -1;
                if (Mathf.Abs(dis) > 1 && !Machine.FaceEquals(dir)) Machine.Filp();
                Machine.XSpeed = Machine.FaceDir * Data.GroundPursuitSpeed;
            }
        }
    }
    public class TestAIInAirIdleState : AnimState<TestAIFsm, TestAIData>
    {
        protected override string CheckCondition()
        {
            // 如果检测到玩家 就往玩家方向移动
            if (Machine.PursuitCheck || Machine.ObserveCheck) return StateName.AirMove;
            return null;
        }
        protected override void Execute(E_StateLife life)
        {
            base.Execute(life);
            Machine.XSpeed = 0;
            // Debug.Log("空中闲置");
        }
    }
    // 追击状态
    public class TestAIPursuitState : AnimState<TestAIFsm, TestAIData>
    {
        private Transform target;
        protected override string CheckCondition()
        {
            if (!Machine.CheckFaceDirIsGround || (!Machine.PursuitCheck && !Machine.ObserveCheck)) return StateName.Observe;
            return null;
        }
        protected override void Execute(E_StateLife life)
        {
            base.Execute(life);
            // 追击目标
            if (Machine.ObserveCheck || Machine.PursuitCheck)
            {
                float dis = Machine.GetColliderTarget("Player").position.x - Machine.transform.position.x;
                int dir = dis > 0 ? 1 : -1;
                if (Mathf.Abs(dis) > 1 && !Machine.FaceEquals(dir)) Machine.Filp();
                Machine.XSpeed = Machine.FaceDir * Data.GroundPursuitSpeed;
            }
        }
    }
    // 观察状态
    public class TestAIObserveState : AnimState<TestAIFsm, TestAIData>
    {
        private Timer mWaitTimer = new Timer();
        protected override string CheckCondition()
        {
            if (Machine.ObserveCheck || Machine.PursuitCheck)
            {
                mWaitTimer.Stop();
                return StateName.Pursuit;
            }
            if (mWaitTimer.IsFinish) return StateName.Patrol;
            return null;
        }
        protected override void Execute(E_StateLife life)
        {
            base.Execute(life);
            switch (life)
            {
                case E_StateLife.Enter:
                    Machine.XSpeed = 0;
                    mWaitTimer.Start(null, Data.ObserveWaitTime, false);
                    break;
                case E_StateLife.Update:
                    mWaitTimer.Update();
                    break;
            }
        }
    }
    // 巡逻状态
    public class TestAIPatrolState : AnimState<TestAIFsm, TestAIData>
    {
        protected override string CheckCondition()
        {
            if (Machine.PursuitCheck) return StateName.Pursuit;
            return null;
        }
        protected override void Execute(E_StateLife life)
        {
            base.Execute(life);

            // 如果前方还可以走 继续移动
            if (Machine.CheckFaceDirIsGround)
            {
                Machine.XSpeed = Data.GroundPatrolSpeed * Machine.FaceDir;
            }
            // 如果前方无路可走 但是在地面上 就转头向后移动
            else if (Machine.CheckGround)
            {
                Machine.Filp();
            }
        }
    }
}